#pragma once

#include <iostream>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <functional>
#include "err.hpp"

namespace violet
{
    using func_t = std::function<std::string (std::string)>;
    const static uint16_t default_port = 8080;//默认端口号

    class udp_server
    {
    public:
        udp_server(func_t cb, uint16_t port = default_port)
        :_port(port)
        ,_service(cb)
        {
            std::cout << "port:" << port << std::endl;
        }

        ~udp_server(){};
        void InitServer()
        {
            // 1.创建socket接口，打开网络文件
            _sock = socket(AF_INET, SOCK_DGRAM, 0);
            if(_sock == -1)
            {
                std::cerr << "创建socket失败：" << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "创建socket成功：" << _sock << std::endl; //3

            struct sockaddr_in local;
            bzero(&local, sizeof(local));//置零，类似memset

            // 给服务器指明IP地址和Port
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);//主机序列转网络序列
            // // inet_addr:将字符串风格ip地址转化为uint32_t，并转为网络序列
            // local.sin_addr.s_addr = inet_addr(_ip.c_str());

            // 云服务器，一般不要指明某一个确定的ip
            local.sin_addr.s_addr = INADDR_ANY; //udp_server启动的时候，bind本主机上任意ip

            int ret = bind(_sock, (const struct sockaddr*)&local, sizeof(local));
            if(ret == -1)
            {
                std::cerr << "套接字绑定失败" << std::endl;
                exit(BIND_ERR);
            }
            std::cerr << "套接字绑定成功" << std::endl;
        }
        void Start()
        {
            char buffer[1024];
            while(1)
            {
                // 收
                // man recvfrom
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);//uint32_t
                int n = recvfrom(_sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
                if(n > 0) buffer[n] = '\0';
                else continue;

                // 提取client信息
                std::string client_ip = inet_ntoa(peer.sin_addr);//ip地址转string风格
                uint16_t client_port = ntohs(peer.sin_port);
                std::cout << client_ip << "-" << client_port << ":" << buffer << std::endl;

                // 处理数据
                std::string message = _service(buffer);
                
                // 发
                // sendto(_sock, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, sizeof(peer));
                sendto(_sock, message.c_str(), message.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
                // netstat -nuap
            }
        }
    private:
        int _sock;
        uint16_t _port;
        // std::string _ip;//之后会去掉
        func_t _service;
    };
}